#include "theaterconst.h"

/* HeadCustomer */
void main() {
	int customerNumber;
	int groupNumber;
	int i, j;
	int sum = 0;
	int myTicketClerk = -1;
	int myConcessionClerk = -1;
	int myTicketTaker = -1;
	int times;
	int pay;
	int popcorn;
	int soda;
	int popcornForGroup = 0;
	int sodaForGroup = 0;
	int minLineNumber;
	int minLineCount;
	int cont;
	int allocated = 0;
	int start;
	int tempSeat;
	int seated;
	int taken;
	int bathroom;
	int arriveTime;
	int price;
	int bathroomTime;
	
	init();
	
	Acquire(idMutex);
	groupNumber = ReadMonitor(headCustomerID, 0);
	SetMonitor(headCustomerID, 0, groupNumber + 1);
	
	for(i = 0; i < groupNumber; i++) {
		sum += CUSTOMERS_PER_GROUP;
	}
	customerNumber = sum;
	Release(idMutex);

	/* assume a customer arrives theater at a ramdom time */
	arriveTime = Rand(100);
	for(i = 0; i < arriveTime; i++) {
		Yield();
	}

	/* the customer arrives */
	/* Acquire(outputLock); */
	prints("HeadCustomer "); print(customerNumber); 
	prints(" in Group "); print(groupNumber); 
	prints(" has entered the movie theater.\n");
	/* Release(outputLock); */
	
	prints("HeadCustomer "); print(customerNumber);
	prints(" of Group "); print(groupNumber);
	prints(" thinks the groupCV number is "); print(groupCV[groupNumber]);
	prints("\n");
	

	Acquire(groupLock[groupNumber]);
	prints("HeadCustomer "); print(customerNumber); prints(" in Group "); print(groupNumber); prints(" sees that "); print(ReadMonitor(groupMV, groupNumber)); prints(" Customers are here...\n");
	if (ReadMonitor(groupMV, groupNumber) != CUSTOMERS_PER_GROUP - 1)	{
	
		/* the head customer waits for every to arrive */
		/* Acquire(outputLock); */
		prints("HeadCustomer "); print(customerNumber); 
		prints(" of Group "); print(groupNumber); 
		prints(" is waiting for the group to form.\n");
		/* Release(outputLock); */
		
		Wait(hcCV[groupNumber], groupLock[groupNumber]);
	}
	
	/* all customers have arrived */
	/* Acquire(outputLock); */
	prints("HeadCustomer "); print(customerNumber); 
	prints(" of Group "); print(groupNumber); 
	prints(" sees all Customers have arrived.\n");
	/* Release(outputLock); */
	
	SetMonitor(groupMV, groupNumber, 0);
	Release(groupLock[groupNumber]);

	/* buy the tickets */
	Acquire(tcLineLock);
	while (myTicketClerk == -1 || ReadMonitor(tcState, myTicketClerk) == C_BREAK) {
		if (myTicketClerk != -1) {
			/* Acquire(outputLock); */
			prints("Customer "); print(customerNumber);
			prints(" in Group "); print(groupNumber);
			prints(" sees TicketClerk "); print(myTicketClerk);
			prints(" is on break.\n");
			/* Release(outputLock); */
		}
		/* fine a ready tc */
		myTicketClerk = -1;
		for(i = 0; i < NUM_TICKET_CLERKS; i++) {
			if (ReadMonitor(tcState, i) == C_READY) {
				myTicketClerk = i;
				SetMonitor(tcState, i, C_BUSY);
				break;
			}
		}

		if (myTicketClerk == -1) {
			/* no one's ready. get in the shortest line */
			int minLineNumber;
			for(i = 0; i < NUM_TICKET_CLERKS; i++) {
				if (ReadMonitor(tcState, i) != C_BREAK) {
					/* there must be at least one tc who's not on break. */
					minLineNumber = i;
					break;
				}
			}
			minLineCount = ReadMonitor(tcLineCount, minLineNumber);
			for(i = minLineNumber+1; i < NUM_TICKET_CLERKS; i++) {
				if (ReadMonitor(tcState, i) != C_BREAK) {
					if (minLineCount > ReadMonitor(tcLineCount, i)) {
						minLineNumber = i;
						minLineCount = ReadMonitor(tcLineCount, i);
					}
				}
			}
			myTicketClerk = minLineNumber;
			SetMonitor(tcLineCount, myTicketClerk, ReadMonitor(tcLineCount, myTicketClerk) + 1);
			
			/* Acquire(outputLock); */
			prints("Customer "); print(customerNumber);
			prints(" in Group "); print(groupNumber);
			prints(" is getting in TicketClerk line "); print(myTicketClerk);
			prints(".\n");
			/* Release(outputLock); */
			times = ReadMonitor(tcBreakTime, myTicketClerk);
			Wait(tcLineCV[myTicketClerk], tcLineLock);
			if (times != ReadMonitor(tcBreakTime, myTicketClerk)) {
				/* Acquire(outputLock); */
				prints("Customer "); print(customerNumber);
				prints(" in Group "); print(groupNumber);
				prints(" sees TicketClerk "); print(myTicketClerk);
				prints(" is on break.\n");
				/* Release(outputLock); */
				myTicketClerk = -1;
				continue;
			}
		}
	}
	Release(tcLineLock);
	/* interact with tc */
	Acquire(tcLock[myTicketClerk]);
	/* tell tc how many tickets */
	
	/* Acquire(outputLock); */
	prints("Customer "); print(customerNumber);
	prints(" in Group "); print(groupNumber);
	prints(" is walking up to TicketClerk "); print(myTicketClerk);
	prints(" to buy "); print(CUSTOMERS_PER_GROUP);
	prints(" tickets.\n");
	/* Release(outputLock); */
	SetMonitor(tcTicket, myTicketClerk, CUSTOMERS_PER_GROUP);
	Signal(tcCV[myTicketClerk],tcLock[myTicketClerk]);
	Wait(tcCV[myTicketClerk],tcLock[myTicketClerk]);
	price = ReadMonitor(tcPrice, myTicketClerk);
	/* pay */
	/* Acquire(outputLock); */
	prints("Customer "); print(customerNumber);
	prints(" in Group "); print(groupNumber);
	prints(" in TicketClerk line "); print(myTicketClerk);
	prints(" is paying $"); print(price);
	prints(".00 for tickets.\n");
	/* Release(outputLock); */
	
	Signal(tcCV[myTicketClerk], tcLock[myTicketClerk]);
	Wait(tcCV[myTicketClerk], tcLock[myTicketClerk]);
	/* leave */
	
	/* Acquire(outputLock); */
	prints("Customer "); print(customerNumber);
	prints(" in Group "); print(groupNumber);
	prints(" is leaving TicketClerk "); print(myTicketClerk);
	prints(".\n");
	/* Release(outputLock); */
	Signal(tcCV[myTicketClerk], tcLock[myTicketClerk]);
	Release(tcLock[myTicketClerk]);

	/* wake up all customers then wait for them to decide if they want food */
	Acquire(groupLock[groupNumber]);
	/* Acquire(outputLock); */
	prints("HeadCustomer "); print(customerNumber);
	prints(" of Group "); print(groupNumber);
	prints(" has told the group to proceed.\n");
	/* Release(outputLock); */
	
	prints("HeadCustomer "); print(customerNumber);
	prints(" of Group "); print(groupNumber);
	prints(" thinks the groupCV number is "); print(groupCV[groupNumber]);
	prints("\n");
	
	Broadcast(groupCV[groupNumber], groupLock[groupNumber]);
	Release(groupLock[groupNumber]);      
	/* wait for every customer to tell him the food status */
	
	/* Acquire(outputLock); */
	prints("HeadCustomer "); print(customerNumber); 
	prints(" of Group "); print(groupNumber); 
	prints(" is waiting for the group to form.\n");
	/* Release(outputLock); */

	Acquire(groupLock[groupNumber]);
	if (ReadMonitor(groupMV, groupNumber) != CUSTOMERS_PER_GROUP - 1) {
		Wait(hcCV[groupNumber], groupLock[groupNumber]);
	}
	SetMonitor(groupMV, groupNumber, 0);
	popcorn = Rand(4);
	soda = Rand(4);
	/* tell the head if the customer wants any food */
	if (popcorn != 0) {
		SetMonitor(customerPopcorn, customerNumber, 1);
	}
	if (soda != 0) {
		SetMonitor(customerSoda, customerNumber, 1);
	}
	Release(groupLock[groupNumber]);
	
	/* Acquire(outputLock); */
	prints("Customer "); print(customerNumber);
	prints(" in Group "); print(groupNumber);
	prints(" wants "); print(ReadMonitor(customerPopcorn, customerNumber));
	prints(" popcorn and "); print(ReadMonitor(customerSoda, customerNumber));
	prints(" soda.\n");
	/* Release(outputLock); */
	
	Acquire(groupLock[groupNumber]);
	/* get the food request from the group members */
	for(i = 0; i < CUSTOMERS_PER_GROUP; i++) {
		/* Acquire(outputLock); */
		prints("Customer "); print(customerNumber);
		prints(" in Group "); print(groupNumber);
		prints(" has "); print(ReadMonitor(customerPopcorn, customerNumber + i));
		prints(" popcorn and "); print(ReadMonitor(customerSoda, customerNumber + i));
		prints(" soda request from a group member.\n");
		/* Release(outputLock); */
		popcornForGroup += ReadMonitor(customerPopcorn, customerNumber + i);
		sodaForGroup += ReadMonitor(customerSoda, customerNumber + i);
	}
	Release(groupLock[groupNumber]);
	/* buy food. get in line */
	Acquire(ccLineLock);
	while (myConcessionClerk == -1 || ReadMonitor(ccState, myConcessionClerk) == C_BREAK) {
		if (myConcessionClerk != -1) {
			/* cc is on break, find another line */
			/* Acquire(outputLock); */
			prints("Customer "); print(customerNumber);
			prints(" in Group "); print(groupNumber);
			prints(" sees ConcessionClerk "); print(myConcessionClerk);
			prints(" is on break.\n");
			/* Release(outputLock); */
		}
		myConcessionClerk = -1;
		for(i = 0; i < NUM_CONCESSION_CLERKS; i++) {
			if (ReadMonitor(ccState, i) == C_READY) {
				myConcessionClerk = i;
				SetMonitor(ccState, i, C_BUSY);
				break;
			}
		}

		if (myConcessionClerk == -1) {
			/* no one's ready. get in the shortest line */
			int minLineNumber;
			for(i = 0; i < NUM_CONCESSION_CLERKS; i++) {
				if (ReadMonitor(ccState, i) != C_BREAK) {
				 	/* there must be at least one tc who's not on break. */
					minLineNumber = i;
					break;
				}
			}
			minLineCount = ReadMonitor(ccLineCount, minLineNumber);
			for(i = minLineNumber+1; i < NUM_CONCESSION_CLERKS; i++) {
				if (ReadMonitor(ccState, i) != C_BREAK) {
					if (minLineCount > ReadMonitor(ccLineCount, i)) {
						minLineNumber = i;
						minLineCount = ReadMonitor(ccLineCount, i);
					}
				}
			}
			myConcessionClerk = minLineNumber;
			SetMonitor(ccLineCount, myConcessionClerk, ReadMonitor(ccLineCount, myConcessionClerk) + 1);
			
			/* Acquire(outputLock); */
			prints("Customer "); print(customerNumber);
			prints(" in Group "); print(groupNumber);
			prints(" is getting in ConcessionClerk line "); print(myTicketClerk);
			prints(".\n");
			/* Release(outputLock); */
			times = ReadMonitor(ccBreakTime, myConcessionClerk);
			Wait(ccLineCV[myConcessionClerk], ccLineLock);
			if (times != ReadMonitor(ccBreakTime, myConcessionClerk)) {
				/* cc is on break and off break, line up again */
				/* Acquire(outputLock); */
				prints("Customer "); print(customerNumber);
				prints(" in Group "); print(groupNumber);
				prints(" sees ConcessionClerk "); print(myTicketClerk);
				prints(" is on break.\n");
				/* Release(outputLock); */				
				myConcessionClerk = -1;
				continue;
			}
		}
	}
	Release(ccLineLock);

	/* interact with cc */
	Acquire(ccLock[myConcessionClerk]);
	/* tell cc how many tickets */
	/* Acquire(outputLock); */
	prints("Customer "); print(customerNumber);
	prints(" in Group "); print(groupNumber);
	prints(" is walking up to ConcessionClerk "); print(myConcessionClerk);
	prints(" to buy "); print(popcornForGroup);
	prints(" popcorn and "); print(sodaForGroup);
	prints(" soda.\n");
	/* Release(outputLock); */
	SetMonitor(ccPopcorn, myConcessionClerk, popcornForGroup);
	SetMonitor(ccSoda, myConcessionClerk, sodaForGroup);
	Signal(ccCV[myConcessionClerk], ccLock[myConcessionClerk]);
	Wait(ccCV[myConcessionClerk], ccLock[myConcessionClerk]);
	price = ReadMonitor(ccPrice, myConcessionClerk);
	/* pay */
	/* Acquire(outputLock); */
	prints("Customer "); print(customerNumber);
	prints(" in Group "); print(groupNumber);
	prints(" in ConcessionClerk line "); print(myConcessionClerk);
	prints(" is paying "); print(price);
	prints(".00 for food.\n");
	/* Release(outputLock); */

	Signal(ccCV[myConcessionClerk], ccLock[myConcessionClerk]);
	Wait(ccCV[myConcessionClerk], ccLock[myConcessionClerk]);
	/* leave */
	/* Acquire(outputLock); */
	prints("Customer "); print(customerNumber);
	prints(" in Group "); print(groupNumber);
	prints(" is leaving ConcessionClerk "); print(myConcessionClerk);
	prints(".\n");
	/* Release(outputLock); */
	
	Signal(ccCV[myConcessionClerk], ccLock[myConcessionClerk]);
	Release(ccLock[myConcessionClerk]);
	
	/* give ticket */
	while (1) {
		/* break if the ticket taker let the group in the theater room */
		myTicketTaker = -1;
		Acquire(ttLineLock);
		while (myTicketTaker == -1 || ReadMonitor(ttState, myTicketTaker) == C_BREAK) {
			if (myTicketTaker != -1) {
				/* tt is on break */
				/* Acquire(outputLock); */
				prints("Customer "); print(customerNumber);
				prints(" in Group "); print(groupNumber);
				prints(" sees TicketTaker "); print(myTicketClerk);
				prints(" is on break.\n");
				/* Release(outputLock); */
			}
			myTicketTaker = -1;
			cont = 0;
			for(i = 0; i < NUM_TICKET_TAKERS; i++) {
				if (ReadMonitor(ttStop, i) != 0) {
					/* there's no seat, goto lobby */
					/* Acquire(outputLock); */
					prints("Customer "); print(customerNumber);
					prints(" in Group "); print(groupNumber);
					prints(" sees TicketTaker "); print(i);
					prints(" is no longer taking tickets. Going to the lobby.\n");
					/* Release(outputLock); */
					
					Acquire(groupLock[groupNumber]);
					/* Acquire(outputLock); */
					prints("HeadCustomer "); print(customerNumber);
					prints(" of Group "); print(groupNumber);
					prints(" has told the group to proceed.\n");
					/* Release(outputLock); */
					
					Broadcast(groupCV[groupNumber], groupLock[groupNumber]);
					Release(groupLock[groupNumber]);
					
					/* Acquire(outputLock); */
					prints("Customer "); print(customerNumber);
					prints(" in Group "); print(groupNumber);
					prints(" is in the lobby.\n");
					/* Release(outputLock); */
					
					Wait(lobbyCV, ttLineLock);
					
					/* Acquire(outputLock); */
					prints("HeadCustomer "); print(customerNumber);
					prints(" of Group "); print(groupNumber);
					prints("  waiting for the group to form.\n");
					/* Release(outputLock); */
					
					/* make sure everyone in group gets into lobby */
					Acquire(groupLock[groupNumber]);
					if (ReadMonitor(groupMV, groupNumber) != CUSTOMERS_PER_GROUP - 1) {
						Wait(hcCV[groupNumber], groupLock[groupNumber]);
					}
					SetMonitor(groupMV, groupNumber, 0);
					Release(groupLock[groupNumber]);
					
					Acquire(groupLock[groupNumber]);
					
					/* Acquire(outputLock); */
					prints("HeadCustomer "); print(customerNumber);
					prints(" of Group "); print(groupNumber);
					prints(" has told the group to proceed.\n");
					/* Release(outputLock); */
					
					/* make everyone leave the lobby */
					Broadcast(groupCV[groupNumber], groupLock[groupNumber]);
					Release(groupLock[groupNumber]);
					
					/* Acquire(outputLock); */
					prints("Customer "); print(customerNumber);
					prints(" in Group "); print(groupNumber);
					prints(" is leaving the lobby.\n");
					/* Release(outputLock); */
					
					/* Acquire(outputLock); */
					prints("HeadCustomer "); print(customerNumber);
					prints(" of Group "); print(groupNumber);
					prints("  waiting for the group to form.\n");
					/* Release(outputLock); */
					
					Acquire(groupLock[groupNumber]);
					if (ReadMonitor(groupMV, groupNumber) != CUSTOMERS_PER_GROUP - 1) {
						Wait(hcCV[groupNumber], groupLock[groupNumber]);
					}
					SetMonitor(groupMV, groupNumber, 0);
					Release(groupLock[groupNumber]);
					cont = 1;
					break;
				}
			}
			if (cont) continue;

			for(i = 0; i < NUM_TICKET_TAKERS; i++) {
				/* find a tt is not busy */
				if (ReadMonitor(ttState, i) == C_READY) {
					myTicketTaker = i;
					SetMonitor(ttState, i, C_BUSY);
					break;
				}
			}

			if (myTicketTaker == -1) {
				/* no one's ready. get in the shortest line */
				minLineNumber;
				for(i = 0; i < NUM_TICKET_TAKERS; i++) {
					if (ReadMonitor(ttState, i) != C_BREAK) {
						/* there must be at least one tc who's not on break. */
						minLineNumber = i;
						break;
					}
				}
				/* gets in shortest line */
				minLineCount = ReadMonitor(ttLineCount, minLineNumber);
				for(i = minLineNumber+1; i < NUM_TICKET_TAKERS; i++) {
					if (ReadMonitor(ttState, i) != C_BREAK) {
						if (minLineCount > ReadMonitor(ttLineCount, i)) {
							minLineNumber = i;
							minLineCount = ReadMonitor(ttLineCount, i);
						}
					}
				}
				myTicketTaker = minLineNumber;
				SetMonitor(ttLineCount, myTicketTaker, ReadMonitor(ttLineCount, myTicketTaker) + 1);
				
				/* Acquire(outputLock); */
				prints("Customer "); print(customerNumber);
				prints(" in Group "); print(groupNumber);
				prints(" is getting in TicketTaker line "); print(myTicketTaker);
				prints(".\n");
				/* Release(outputLock); */
				times = ReadMonitor(ttBreakTime, myTicketTaker);
				Wait(ttLineCV[myTicketTaker], ttLineLock);
				if (times != ReadMonitor(ttBreakTime, myTicketTaker)) {
					/* the ticket taker is on break and off break, line up again */
					/* Acquire(outputLock); */
					prints("Customer "); print(customerNumber);
					prints(" in Group "); print(groupNumber);
					prints(" sees TicketTaker "); print(myTicketTaker);
					prints(" is on break.\n");
					/* Release(outputLock); */
					myTicketTaker = -1;
					continue;
				}
			}
		}
		if (ReadMonitor(ttStop, myTicketTaker) != 0) {
			/* there's no seat, goto lobby */
			/* Acquire(outputLock); */
			prints("Customer "); print(customerNumber);
			prints(" in Group "); print(groupNumber);
			prints(" sees TicketTaker "); print(myTicketTaker);
			prints(" is no longer taking tickets. Going to the lobby.\n");
			/* Release(outputLock); */

			Acquire(groupLock[groupNumber]);
			/* Acquire(outputLock); */
			prints("HeadCustomer "); print(customerNumber);
			prints(" of Group "); print(groupNumber);
			prints(" has told the group to proceed.\n");
			/* Release(outputLock); */
			
			Broadcast(groupCV[groupNumber], groupLock[groupNumber]);
			Release(groupLock[groupNumber]);
			
			/* Acquire(outputLock); */
			prints("Customer "); print(customerNumber);
			prints(" in Group "); print(groupNumber);
			prints(" is in the lobby.\n");
			/* Release(outputLock); */
			
			Wait(lobbyCV, ttLineLock);
			
			/* Acquire(outputLock); */
			prints("HeadCustomer "); print(customerNumber);
			prints(" of Group "); print(groupNumber);
			prints("  waiting for the group to form.\n");
			/* Release(outputLock); */
			
			/* make sure everyone in group gets into lobby */
			Acquire(groupLock[groupNumber]);
			if (ReadMonitor(groupMV, groupNumber) != CUSTOMERS_PER_GROUP - 1) {
				Wait(hcCV[groupNumber], groupLock[groupNumber]);
			}
			SetMonitor(groupMV, groupNumber, 0);
			Release(groupLock[groupNumber]);
			
			Acquire(groupLock[groupNumber]);
			
			/* Acquire(outputLock); */
			prints("HeadCustomer "); print(customerNumber);
			prints(" of Group "); print(groupNumber);
			prints(" has told the group to proceed.\n");
			/* Release(outputLock); */
			
			Broadcast(groupCV[groupNumber], groupLock[groupNumber]);
			Release(groupLock[groupNumber]);
			
			/* Acquire(outputLock); */
			prints("Customer "); print(customerNumber);
			prints(" in Group "); print(groupNumber);
			prints(" is leaving the lobby.\n");
			/* Release(outputLock); */
			
			/* Acquire(outputLock); */
			prints("HeadCustomer "); print(customerNumber);
			prints(" of Group "); print(groupNumber);
			prints("  waiting for the group to form.\n");
			/* Release(outputLock); */
			
			Acquire(groupLock[groupNumber]);
			if (ReadMonitor(groupMV, groupNumber) != CUSTOMERS_PER_GROUP - 1) {
				Wait(hcCV[groupNumber], groupLock[groupNumber]);
			}
			SetMonitor(groupMV, groupNumber, 0);
			Release(groupLock[groupNumber]);
			continue;
		}
		Release(ttLineLock);
		/* interact with tt */
		Acquire(ttLock[myTicketTaker]);
		SetMonitor(ttTicket, myTicketTaker, CUSTOMERS_PER_GROUP);
		Signal(ttCV[myTicketTaker], ttLock[myTicketTaker]);
		Wait(ttCV[myTicketTaker], ttLock[myTicketTaker]);
		Acquire(ttLineLock);
		if (ReadMonitor(ttStop, myTicketTaker) != 0 || ReadMonitor(ttProcess, myTicketTaker) == 0) {
			Release(ttLock[myTicketTaker]);
			/* Acquire(outputLock); */
			prints("Customer "); print(customerNumber);
			prints(" in Group "); print(groupNumber);
			prints(" sees TicketTaker "); print(myTicketTaker);
			prints(" is no longer taking tickets. Going to the lobby.\n");
			/* Release(outputLock); */

			Acquire(groupLock[groupNumber]);
			/* Acquire(outputLock); */
			prints("HeadCustomer "); print(customerNumber);
			prints(" of Group "); print(groupNumber);
			prints(" has told the group to proceed.\n");
			/* Release(outputLock); */
			
			Broadcast(groupCV[groupNumber], groupLock[groupNumber]);
			Release(groupLock[groupNumber]);
			
			/* Acquire(outputLock); */
			prints("Customer "); print(customerNumber);
			prints(" in Group "); print(groupNumber);
			prints(" is in the lobby.\n");
			/* Release(outputLock); */
			
			Wait(lobbyCV, ttLineLock);
			
			/* Acquire(outputLock); */
			prints("HeadCustomer "); print(customerNumber);
			prints(" of Group "); print(groupNumber);
			prints("  waiting for the group to form.\n");
			/* Release(outputLock); */
			
			/* make sure everyone in group gets into lobby */
			Acquire(groupLock[groupNumber]);
			if (ReadMonitor(groupMV, groupNumber) != CUSTOMERS_PER_GROUP - 1) {
				Wait(hcCV[groupNumber], groupLock[groupNumber]);
			}
			SetMonitor(groupMV, groupNumber, 0);
			Release(groupLock[groupNumber]);
			
			Acquire(groupLock[groupNumber]);
			
			/* Acquire(outputLock); */
			prints("HeadCustomer "); print(customerNumber);
			prints(" of Group "); print(groupNumber);
			prints(" has told the group to proceed.\n");
			/* Release(outputLock); */
			
			Broadcast(groupCV[groupNumber], groupLock[groupNumber]);
			Release(groupLock[groupNumber]);
			
			/* Acquire(outputLock); */
			prints("Customer "); print(customerNumber);
			prints(" in Group "); print(groupNumber);
			prints(" is leaving the lobby.\n");
			/* Release(outputLock); */
			
			/* Acquire(outputLock); */
			prints("HeadCustomer "); print(customerNumber);
			prints(" of Group "); print(groupNumber);
			prints("  waiting for the group to form.\n");
			/* Release(outputLock); */
			
			Acquire(groupLock[groupNumber]);
			if (ReadMonitor(groupMV, groupNumber) != CUSTOMERS_PER_GROUP - 1) {
				Wait(hcCV[groupNumber], groupLock[groupNumber]);
			}
			SetMonitor(groupMV, groupNumber, 0);
			Release(groupLock[groupNumber]);
			Release(ttLineLock);
			continue;
		} else {
			Release(ttLineLock);
			/* Acquire(outputLock); */
			prints("Customer "); print(customerNumber);
			prints(" in Group "); print(groupNumber);
			prints(" is leaving TicketTaker "); print(myTicketTaker);
			prints(".\n");
			/* Release(outputLock); */
			Signal(ttCV[myTicketTaker], ttLock[myTicketTaker]);
			Release(ttLock[myTicketTaker]);
			break;
		}
	}

	Acquire(groupLock[groupNumber]);
	/* allocate seat here */
	Acquire(seatMutex);
	for(seated = 0; seated < CUSTOMERS_PER_GROUP; seated++) {
		SetMonitor(customerSeat, customerNumber + seated, 1);
	}
	
	Release(seatMutex);
	/* Acquire(outputLock); */
	prints("HeadCustomer "); print(customerNumber);
	prints(" of Group "); print(groupNumber);
	prints(" has told the group to proceed.\n");
	/* Release(outputLock); */

	Broadcast(groupCV[groupNumber], groupLock[groupNumber]);
	
	/* Acquire(outputLock); */
	prints("Customer "); print(customerNumber);
	prints(" in Group "); print(groupNumber);
	prints(" has been seated");
	prints(".\n");
	/* Release(outputLock); */
	Release(groupLock[groupNumber]);

	/* see the movie */
	Acquire(movieLock);
	/* Acquire(outputLock); */
	prints("Customer "); print(customerNumber);
	prints(" in Group "); print(groupNumber);
	prints(" in sitting in a theater room seat.\n");
	/* Release(outputLock); */
	
	SetMonitor(customerReadyWatchingMovie, 0, ReadMonitor(customerReadyWatchingMovie, 0) + 1);
	
	prints("Customer "); print(customerNumber);
	prints(" in Group "); print(groupNumber);
	prints(" sees "); print(ReadMonitor(customerReadyWatchingMovie, 0));
	prints(" Customers sitting in the screening room\n");
	
	/* watch the movie */
	Wait(movieCV, movieLock);
	SetMonitor(customerReadyWatchingMovie, 0, ReadMonitor(customerReadyWatchingMovie, 0) - 1);
	
	prints("Customer "); print(customerNumber);
	prints(" in Group "); print(groupNumber);
	prints(" sees "); print(ReadMonitor(customerReadyWatchingMovie, 0));
	prints(" Customers remaining in the screening room\n");
	
	/* Acquire(outputLock); */
	prints("Customer "); print(customerNumber);
	prints(" in Group "); print(groupNumber);
	prints(" in getting out of a theater room seat.\n");
	/* Release(outputLock); */
	Release(movieLock);

	/* wait for the customers tell him if they are going to the bathroom */
	/* Acquire(outputLock); */
	prints("HeadCustomer "); print(customerNumber);
	prints(" of Group "); print(groupNumber);
	prints("  waiting for the group to form.\n");
	/* Release(outputLock); */
	
	Acquire(groupLock[groupNumber]);
	if (ReadMonitor(groupMV, groupNumber) != CUSTOMERS_PER_GROUP - 1) {
		Wait(hcCV[groupNumber], groupLock[groupNumber]);
	}
	SetMonitor(groupMV, groupNumber, 0);
	Release(groupLock[groupNumber]);

	/* decide if go to bathroom */
	bathroom = Rand(4);
	if (bathroom == 0) {
		/* go to the bathroom */
		Acquire(bathroomLock);
		/* Acquire(outputLock); */
		prints("Customer "); print(customerNumber);
		prints(" in Group "); print(groupNumber);
		prints(" is going to the bathroom.\n");
		/* Release(outputLock); */
		bathroomTime = Rand(5);
		for(i = 0; i < bathroomTime; i++) {
			Yield();
		}
		/* Acquire(outputLock); */
		prints("Customer "); print(customerNumber);
		prints(" in Group "); print(groupNumber);
		prints(" is leaving to the bathroom.\n");
		/* Release(outputLock); */
		Release(bathroomLock);
	}
	
	/* Acquire(outputLock); */
	prints("Customer "); print(customerNumber);
	prints(" in Group "); print(groupNumber);
	prints(" is in the lobby.\n");
	/* Release(outputLock); */

	Acquire(groupLock[groupNumber]);
	if (ReadMonitor(groupBathroomMV, groupNumber) != ReadMonitor(customerBathroomNumber, groupNumber)) {
		Wait(groupBathroomCV[groupNumber], groupLock[groupNumber]);
	}
	
	/* Acquire(outputLock); */
	prints("HeadCustomer "); print(customerNumber);
	prints(" of Group "); print(groupNumber);
	prints(" has told the group to proceed.\n");
	/* Release(outputLock); */
	Broadcast(groupCV[groupNumber], groupLock[groupNumber]);
	/* Acquire(outputLock); */
	prints("Customer "); print(customerNumber);
	prints(" in Group "); print(groupNumber);
	prints(" is leaving the lobby.\n");
	/* Release(outputLock); */
	Release(groupLock[groupNumber]);

	/* all set, leave */
	Acquire(leaveMutex);
	SetMonitor(leaveCount, 0, ReadMonitor(leaveCount, 0) + 1);
	/* Acquire(outputLock); */
	prints("Customer "); print(customerNumber);
	prints(" in Group "); print(groupNumber);
	prints(" has left the movie theater.\n");
	/* Release(outputLock); */
	Release(leaveMutex);
	Exit(0);
}